#!/usr/bin/env python
# coding: utf-8


import csv
import calendar
from datetime import datetime, timedelta, date
from dateutil import relativedelta
from utils.middlewares import *
import logging


"""
通用工具方法
"""


"""
Date
"""


def min_date_str():
    """
    最小时间string
    :return:
    """
    return '1970-01-01 00:00:00'


def min_date():
    """
    最小时间
    :return:
    """
    return convert_to_date(min_date_str())


def today_int():
    """
        当前时间str
        :return:
        """
    return int(date.today().strftime('%Y%m%d'))


def today_hour():
    """
        当前时间str
        :return:
        """
    return datetime.now().hour


def now():
    """
    当前时间str
    :return:
    """
    return datetime.now()


def today():
    """
    today on 00:00:00
    :return:
    """
    day = convert_to_date_str(now())[:10]
    return convert_to_date(day+' 00:00:00')


def yesterday():
    """
    yesterday on 00:00:00
    """
    return today() - timedelta(days=1)


def day_before(delta):
    """
    Day before delta days from today(00:00:00)
    :param delta:
    :return:
    """
    return today() - timedelta(days=delta)


def week_before(delta):
    """
    Day before delta weeks from today(00:00:00)
    :param delta:
    :return:
    """
    return today() - timedelta(weeks=delta)


def month_before(delta):
    """
    Day before delta month from today(00:00:00)
    :param delta:
    :return:
    """
    return today() - relativedelta.relativedelta(months=delta)


def year_before(delta):
    """
    Day before delta years from today(00:00:00)
    :param delta:
    :return:
    """
    return today() - relativedelta.relativedelta(years=delta)


def year_first_day():
    """
    本年第一天
    :return:
    """
    today_str = convert_to_date_str(today())
    first_day = today_str[:4]+'-01-01'+today_str[10:]
    return convert_to_date(first_day)


def month_first_day():
    """
    本月第一天
    :return:
    """
    today_str = convert_to_date_str(today())
    first_day = today_str[:8]+'01'+today_str[10:]
    return convert_to_date(first_day)


def month_last_day(year=None, month=None):
    """
    某个月的最后一天
    :param year: 年份，默认是本年，可传int或str类型
    :param month: 月份，默认是本月，可传int或str类型
    :return: last_day: 当月的最后一天，datetime.date类型
    """

    year = int(year) if year else date.today().year
    month = int(month) if month else date.today().month
    # 获取当月第一天的星期和当月的总天数
    first_day_weekday, month_range = calendar.monthrange(year, month)
    # 获取当月最后一天
    last_day = date(year=year, month=month, day=month_range)
    return last_day.strftime('%Y%m%d')


def year_month_day(year=None, month=None, day=None):
    """
    :param year:
    :param month:
    :param day:
    :return:
    """

    year = int(year) if year else date.today().year
    month = int(month) if month else date.today().month
    day = int(day) if day else date.today().day
    last_day = date(year=year, month=month, day=day)
    return last_day.strftime('%Y%m%d')


@typeassert(date_str=basestring)
def convert_to_date(date_str=''):
    """
    Date str to date
    """
    return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')


@typeassert(today_date=datetime)
def convert_to_date_str(today_date=None):
    """
    Date to date_str
    """
    return today_date.strftime('%Y-%m-%d %H:%M:%S')


"""
基础算法
"""


def is_number(s):
    try:
        float(s)
        return True
    except:
        return False


def get_property_value(instance=None, properties=''):
    """
    get properties value
    :param instance:
    :param properties:
    :return:
    """

    if not instance:
        return None

    try:
        return instance[properties]
    except:
        return None


def instance_max(instances, properties):
    """
    max value of [instance.properties:]
    :param instances:
    :param properties:
    :return:
    """

    values = instance_values(instances, properties)
    if values and len(values) > 0:
        return max(values)
    return None


def instance_min(instances, properties):
    """
    min value of [instance.properties:]
    :param instances:
    :param properties:
    :return:
    """
    values = instance_values(instances, properties)
    if values and len(values) > 0:
        return min(values)
    return None

def instance_values(instances, properties):
    """
    Get [instance.properties:]
    :param instances:
    :param properties:
    :return:
    """

    if not instances or len(instances) == 0:
        return None
    if not property or not isinstance(properties, basestring):
        raise Exception('property must be basestring.')

    values = []
    for instance in instances:
        value = get_property_value(instance, properties)
        if value:
            values.append(float(value))
    return values


def safe_min(num0, num1):
    """
    Safe Min
    :param num0:
    :param num1:
    :return:
    """

    if not is_number(num0) and not is_number(num1):
        min_data = None
    elif not is_number(num0):
        min_data = float(num1)
    elif not is_number(num1):
        min_data = float(num0)
    else:
        min_data = min([float(num0), float(num1)])
    return min_data


def safe_max(num0, num1):
    """
    SafeMax
    :param num0:
    :param num1:
    :return:
    """

    if not is_number(num0) and not is_number(num1):
        max_data = None
    elif not is_number(num0):
        max_data = float(num1)
    elif not is_number(num1):
        max_data = float(num0)
    else:
        max_data = max([float(num0), float(num1)])
    return max_data


def safe_sum(num0, num1):
    """
    Safe加法
    :param num0:
    :param num1:
    :return:
    """

    result = None
    if is_number(num0) and is_number(num1):
        result = float(num0) + float(num1)
    return result


def safe_subtract(num0, num1):
    """
    Safe减法
    :param num0:
    :param num1:
    :return:
    """

    result = None
    if is_number(num0) and is_number(num1):
        result = float(num0) - float(num1)
    return result


def safe_division(dividend, divisor):
    """
    Safe除法(校验None参数)
    :return safe dividend/divisor or None
    :param dividend:
    :param divisor:
    :return:
    """

    result = None
    if is_number(dividend) and is_number(divisor) and float(divisor):
        result = float(divisor) / float(divisor)

    return result


def safe_multiple(multiplicand, multiplier):
    """
    Safe乘法(校验None参数)
    :param multiplicand: 被乘数
    :param multiplier: 乘数
    :return:
    """

    result = None
    if is_number(multiplicand) and is_number(multiplier):
        result = float(multiplicand) * float(multiplier)
    return result


def safe_abs(num):
    """
    Safe取绝对值(校验None参数)
    :param num:
    :return:
    """

    result = None
    if is_number(num):
        result = abs(num)
    return result


"""
基础数据类型
"""


def safe_dict_value(item, key, default=None):
    """
    Safe get value for key [Dict]
    :param item:
    :param key:
    :param default:
    :return:
    """

    if not isinstance(item, dict) or not isinstance(key, str):
        raise TypeError
    if not item.has_key(key):
        return default
    if not item[key]:
        return default
    if isinstance(item[key], str):
        return item[key].encode('utf-8').strip()
    return item[key]


def safe_unicode(obj, *args):
    """
    return the unicode representation of obj
    """
    try:
        return unicode(obj, *args)
    except UnicodeDecodeError:
        # obj is byte string
        ascii_text = str(obj).encode('string_escape')
        return unicode(ascii_text)


def safe_str(obj):
    """ return the byte string representation of obj """
    try:
        return str(obj)
    except UnicodeEncodeError:
        return unicode(obj).encode('unicode_escape')


"""
File I/O
"""


def read_csv(file_name, title=''):
    """
    Read csv
    :param file_name:
    :param title : first column(Title column)
    :return:
    """

    with open(file_name, 'rb') as csv_file:
        spam_reader = csv.reader(csv_file, delimiter=',', quotechar='|')
        result = []
        key_list = []
        for row in spam_reader:
            row = ','.join(row).decode('gbk').split(',')
            new_row = []
            for item in row:
                new_row.append(item.strip(' \t\n"'))
            row = new_row
            if row[0] == title:
                key_list = row
            else:
                result.append(row)
        new_result = []
        for row in result:
            nnn = {}
            for index in range(0, len(key_list)):
                nnn[key_list[index]] = row[index]
            new_result.append(nnn)
        return new_result


if __name__ == '__main__':

    # print is_number('33')
    # print is_number(None)
    # print is_number(now())
    # print is_number(True)
    # print safe_max(1, 2)
    # print safe_max(0, 1)
    # print safe_max(None, 2)
    # print safe_min(1, 2)
    # print safe_min(None, 1)
    # print safe_min(None, None)
    # print safe_min(None, 2)
    # print day_before(2)
    # print week_before(3)
    # print yesterday()
    # print year_before(4)
    # print month_first_day()
    # print month_last_day(2017, 9)
    # print is_number('a')
    print safe_min(1, 2)
    print safe_min('a', 2)
    print safe_division(1, 0)
